﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Hypermarket_Serial_Port
{
    class CheckOutManager : CashierRegisterTaskManager
    {

        #region Constructor
        public CheckOutManager()
        {
        }
        #endregion

        
        #region Checkout operation
        public override List<string> TaskOperation(List<string> receivedInfoList, Dictionary<string, CashierRegister> cashierDict)
        {
            try
            {
                SerialPortLog.Log("Checkout Start");
                CashierRegister cashierRegister;
                string machineID = receivedInfoList[Constant.ZERO];
                string type = receivedInfoList[Constant.ONE];
                SerialPortLog.LogOperation("Checkout Start: " + machineID);
                if (cashierDict.TryGetValue(machineID, out cashierRegister))
                {
                    if(cashierRegister.isTransactionStarted())
                    {
                        List<Transaction> TransactionList = cashierRegister.getTransactionList();
                        if (TransactionList.Count == Constant.ZERO)
                        {
                            List<string> output = new List<string>();
                            output.Add(machineID);
                            output.Add(type);
                            output.Add(Constant.FAIL);
                            SerialPortLog.LogOperation("Checkout Fail");
                            SerialPortLog.Log("Checkout Fail");
                            return output;
                            //return Constant.ADD_TRANSACTION_FIRST;
                        }    
                        else
                            if (cashierRegister.CheckOut())
                            {
                                return ProcessCheckOut(cashierRegister, machineID, TransactionList, type);
                            }
                            else
                            {
                                List<string> output = new List<string>();
                                output.Add(machineID);
                                output.Add(type);
                                output.Add(Constant.FAIL);
                                SerialPortLog.LogOperation("Checkout Fail");
                                SerialPortLog.Log("Checkout Fail");
                                return output;
                            }
                    }
                    else
                    {
                        List<string> output = new List<string>();
                        output.Add(machineID);
                        output.Add(type);
                        output.Add(Constant.FAIL);
                        SerialPortLog.LogOperation("Checkout Fail");
                        SerialPortLog.Log("Checkout Fail");
                        return output;
                        //return Constant.START_TRANSACTION_FIRST;
                    }
                }
                else
                {
                    List<string> output = new List<string>();
                    output.Add(machineID);
                    output.Add(type);
                    output.Add(Constant.FAIL);
                    SerialPortLog.LogOperation("Checkout Fail");
                    SerialPortLog.Log("Checkout Fail");
                    return output;
                    //return Constant.LOGIN_FIRST_MSG;
                }
            }
            catch
            {
                SerialPortLog.LogOperation("Checkout Error");
                SerialPortLog.Log("Checkout Error");
                throw;
            }
        }

        private List<string> ProcessCheckOut(CashierRegister cashierRegister, string machineID, List<Transaction> TransactionList, string type)
        {
            mDBManager.AddTransactionDataRow(cashierRegister.getTransactionID(), cashierRegister.getCashierID(), machineID, cashierRegister.getTransactionDate()); //receipt
            //string output = Constant.TRANSACTION_ID + Constant.COLON + Constant.SPACE + cashierRegister.getTransactionID();
            double subtotal = Constant.DOUBLE_INITIAL_VALUE;
            double realtotalPrice = Constant.DOUBLE_INITIAL_VALUE;
            foreach (Transaction tr in TransactionList)
            {
                SerialPortLog.Log(tr.Barcode);
                SerialPortLog.Log(tr.UnitSold.ToString());
                //mDBManager.AddCheckOutItemDataRow(cashierRegister.getTransactionID(), tr.Barcode, Convert.ToDateTime(tr.BatchID),
                //   Convert.ToDouble(tr.CostPirce), Convert.ToDouble(tr.SellingPrice), Convert.ToDouble(tr.Discount), tr.UnitSold);

                DataRow[] discountRows = GetDiscountProductDataRows(tr.Barcode);
                if (discountRows.Count() == Constant.ZERO)  //no discount, sellingPrice
                {
                    //output = output + Constant.NEWLINE + Constant.PURCHASED_ITEM_MSG + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + tr.Barcode
                    //         + Constant.NEWLINE + Constant.NAME + Constant.COLON + Constant.SPACE + tr.ProductName + Constant.NEWLINE + Constant.SELLING_PRICE
                    //         + Constant.COLON + Constant.SPACE + Constant.DALLOR + tr.SellingPrice + Constant.NEWLINE + Constant.QUANTITY + Constant.COLON +
                    //         Constant.SPACE + tr.UnitSold + Constant.NEWLINE;
                    //subtotal = subtotal + Convert.ToDouble(tr.SellingPrice) * Convert.ToInt32(tr.UnitSold); 
                    //NoDiscount(tr.Barcode, tr.UnitSold, cashierRegister, machineID, type);
                    mDBManager.AddCheckOutItemDataRow(cashierRegister.getTransactionID(), tr.Barcode, Convert.ToDateTime(tr.BatchID),
                            Convert.ToDouble(tr.CostPirce), Convert.ToDouble(tr.SellingPrice), Convert.ToDouble(tr.Discount), tr.UnitSold);
                    subtotal += 0;
                    realtotalPrice += (Convert.ToDouble(tr.SellingPrice) * tr.UnitSold);
                }
                else
                {
                    //double newPrice = Convert.ToDouble(tr.SellingPrice) * (100 - Convert.ToDouble(tr.Discount)) / 100;
                    //output = output + Constant.NEWLINE + Constant.PURCHASED_ITEM_MSG + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + tr.Barcode + Constant.NEWLINE + Constant.NAME +
                    //         Constant.COLON + Constant.SPACE + tr.ProductName + Constant.NEWLINE + Constant.SELLING_PRICE + Constant.COLON + Constant.SPACE + Constant.DALLOR +
                    //         tr.SellingPrice + Constant.NEWLINE + Constant.DISCOUNT + Constant.COLON + Constant.SPACE + Constant.DALLOR + Math.Round(Convert.ToDecimal(newPrice), Constant.TWO)
                    //         + Constant.NEWLINE + Constant.QUANTITY + Constant.COLON + Constant.SPACE + tr.UnitSold + Constant.NEWLINE;
                    //subtotal = subtotal + Convert.ToDouble(newPrice) * Convert.ToInt32(tr.UnitSold);
                    double discount = HaveDiscount(tr.Barcode, tr.UnitSold, discountRows.First(), cashierRegister, machineID, type, ref subtotal, ref realtotalPrice);
                    int intDiscount = Convert.ToInt32(discount);
                    mDBManager.AddCheckOutItemDataRow(cashierRegister.getTransactionID(), tr.Barcode, Convert.ToDateTime(tr.BatchID),
                            Convert.ToDouble(tr.CostPirce), Convert.ToDouble(tr.SellingPrice), Convert.ToDouble(intDiscount), tr.UnitSold);
                }
            }
            //subtotal = Convert.ToDouble(Math.Round(Convert.ToDecimal(subtotal), Constant.TWO));
            //output = output + Constant.NEWLINE + Constant.TOTALPRICE_MSG + subtotal.ToString();
            List<string> output = new List<string>();
            output.Add(machineID);
            output.Add(type);
            output.Add(Constant.SUCCESS);
            output.Add(subtotal.ToString());
            double finalSoundTotal = realtotalPrice - subtotal;
            finalSoundTotal = (double)Math.Round((finalSoundTotal), Constant.TWO);
            output.Add(finalSoundTotal.ToString());
            /**add sound index**/
            SerialPortLog.LogOperation("Real Total Price:"+ realtotalPrice);
            SerialPortLog.LogOperation("Total Price:" + finalSoundTotal);
            SerialPortLog.LogOperation("Subtotal Price:" + subtotal);
            SerialPortLog.LogOperation("Checkout Successfully");
            return output;
        }
        #endregion 


        #region Have Discount

        private DataRow[] GetDiscountProductDataRows(string productID)
        {
            DataTable StockProductDiscount = mDBManager.getTable(Constant.STOCK_PRODUCT_DISCOUNT_TABLE);
            string query = Constant.PRODUCT_ID + Constant.EQUAL + Constant.SINGAL_QUOTE + productID +
                    Constant.SINGAL_QUOTE + Constant.AND + Constant.EXPIRE_DATE + Constant.MORE_THAN +
                    Constant.SINGAL_QUOTE + DateTime.Today + Constant.SINGAL_QUOTE;
            DataRow[] discountRows = StockProductDiscount.Select(query);  //query add barcode, batchID, costprice
            return discountRows;
        }

        private static double HaveDiscount(string productID, int quantity, DataRow dr, CashierRegister cashierRegister, string machineID, string type, ref double subtotal, ref double displaytotal)
        {
            if (Convert.ToInt32(quantity) < Convert.ToInt32(dr[Constant.BUNDLE_UNIT]))
            {
                string name = dr[Constant.NAME].ToString();
                string sellingPrice = dr[Constant.SELLING_PRICE].ToString();
                string batchID = dr[Constant.BATCH_ID].ToString();
                string importPrice = dr[Constant.IMPORT_PRICE].ToString();
                //cashierRegister.AddTransaction(productID, name, batchID, importPrice, sellingPrice, Constant.ZERO_PERCENTAGE, Convert.ToInt32(quantity)); //for database report purpose
                //string output = Constant.MSG_SCANNED + Constant.COLON + Constant.NEWLINE + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + productID 
                //                + Constant.SPACE + name + Constant.NEWLINE + Constant.SELLING_PRICE + Constant.COLON + Constant.SPACE + 
                //                Math.Round(Convert.ToDecimal(sellingPrice), Constant.TWO) + Constant.NEWLINE /***sound index****/;
                subtotal += Constant.ZERO;
                displaytotal += (Convert.ToDouble(sellingPrice) * quantity);
                return Constant.ZERO;
            }
            else// if ((Convert.ToInt32(dr[Constant.FREE_ITEM_QUANTITY]) > Constant.MIN_DISCOUNT) || (Convert.ToInt32(dr[Constant.DISCOUNT]) > Constant.MIN_DISCOUNT))
            {
                double discount = CalculateDiscountPrice(productID, quantity, dr, cashierRegister, machineID, type, ref subtotal, ref displaytotal);
                return discount;
            }
            //else
            //{
            //    //List<string> tempStr = new List<string>();
            //    //tempStr.Add(machineID);
            //    //tempStr.Add(type);
            //    //tempStr.Add(Constant.FAIL);
            //    //return tempStr;
            //    //tempStr.Add(Constant.PROGRAM_ERROR);
            //}
        }

        private static double CalculateDiscountPrice(string productID, int quantity, DataRow dr, CashierRegister cashierRegister, string machineID, string type, ref double subtotal, ref double displaytotal)
        {
            string name = dr[Constant.NAME].ToString();
            double sellingPrice = Convert.ToDouble(dr[Constant.SELLING_PRICE]);
            string batchID = dr[Constant.BATCH_ID].ToString();
            string importPrice = dr[Constant.IMPORT_PRICE].ToString();
            double BuPrice = (sellingPrice * Convert.ToInt32(quantity)) / (Convert.ToInt32(quantity) + Convert.ToInt32(dr[Constant.FREE_ITEM_QUANTITY]));
            double finalPrice = BuPrice * (100 - Convert.ToInt32(dr[Constant.DISCOUNT])) / 100;
            double discount = 100 - (finalPrice / sellingPrice) * 100;
            finalPrice = (double)Math.Round(Convert.ToDecimal(finalPrice), Constant.TWO);
            //cashierRegister.AddTransaction(productID, name, batchID, importPrice, sellingPrice.ToString(), discount.ToString(), Convert.ToInt32(quantity)); //for database report purpose 
            //string output = Constant.MSG_SCANNED + Constant.COLON + Constant.NEWLINE + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + productID + Constant.NEWLINE + 
            //                Constant.NAME + Constant.COLON + Constant.SPACE + name + Constant.NEWLINE + Constant.SELLING_PRICE + Constant.COLON + Constant.SPACE + 
            //                Math.Round(Convert.ToDecimal(finalPrice), Constant.TWO) + Constant.NEWLINE + Constant.QUANTITY + Constant.COLON + Constant.SPACE + quantity + Constant.NEWLINE/***sound index****/;
            subtotal += (double)Math.Round(Convert.ToDecimal(sellingPrice * quantity - finalPrice * quantity), Constant.TWO);
            displaytotal += (Convert.ToDouble(sellingPrice) * quantity);
            return discount;
        }
        
        #endregion
    }
}
